
#pragma once
#include "ParticleSystem.h"
#include "../TinyXml/tinyxml.h"
#include <ctime>

ParticleSystem* ParticleSystem::GetInstance(void)
{
	static ParticleSystem s_Instance;

	return &s_Instance;
}


void ParticleSystem::Init()
{
	m_PShapes = SGD::GraphicsManager::GetInstance()->LoadTexture(
		L"resource/data/ParticleShapes.png");

	srand(unsigned int(time(0)));

	count = 0;
}


void ParticleSystem::Exit()
{
	
	 SGD::GraphicsManager::GetInstance()->UnloadTexture(m_PShapes);
	 
	 delete[] FWstats.FWimageID;
	 
	 FWstats.FWimageID = NULL;
	 
}


bool ParticleSystem::LoadEmitter(const char* filename)
{
	TiXmlDocument document;

	ParticleSystem::Init();

	// Load the file
	if (document.LoadFile(filename) == false)
		return false;

	TiXmlElement* effect;

	effect = document.RootElement();

	if (effect == nullptr)
		return false;

	//Find Emitter
	TiXmlElement* emitter = effect->FirstChildElement("Emitter");

	//Set values for failure test
	EMstats.EMheight = -1;
	EMstats.EMwidth = -1;
	EMstats.EMloop = 1;
	EMstats.EMmax = -1;
	EMstats.EMposx = -1;
	EMstats.EMposy = -1;
	EMstats.EMshape = 1;
	EMstats.EMspawnrate = -1;
	EMstats.EMvelocity = -1;

	//Load Emitter
	if (emitter != nullptr)
	{
		
		//For the Emitter
		emitter->Attribute("max", &EMstats.EMmax);
		emitter->QueryFloatAttribute("spawnrate", &EMstats.EMspawnrate);	
		emitter->QueryFloatAttribute("posx", &EMstats.EMposx);				
		emitter->QueryFloatAttribute("posy", &EMstats.EMposy);				
		emitter->QueryFloatAttribute("velocity", &EMstats.EMvelocity);		
		emitter->QueryIntAttribute("loop", &EMstats.EMloop);				
		emitter->QueryFloatAttribute("width", &EMstats.EMwidth);			
		emitter->QueryFloatAttribute("height", &EMstats.EMheight);			
		emitter->QueryIntAttribute("shape", &EMstats.EMshape);				 

	}


	TiXmlElement* particle = emitter->NextSiblingElement("Particle");

	//Set values for failure test
	PAstats.Pvelocityx = -1;
	PAstats.Pvelocityy = -1;
	PAstats.Plifetimer = -1;
	PAstats.Palpha = -1;
	PAstats.Pred = -1;
	PAstats.Pgreen = -1;
	PAstats.Pblue = -1;
	PAstats.Protationx = -1;
	PAstats.Pscalex = -1;
	PAstats.Pscaley = -1;




	if (particle != nullptr)
	{
		//For the Particle
		particle->QueryFloatAttribute("velocityx", &PAstats.Pvelocityx);	
		particle->QueryFloatAttribute("velocityy", &PAstats.Pvelocityy);	 
		particle->QueryFloatAttribute("lifetimer", &PAstats.Plifetimer);	
		particle->QueryIntAttribute("alpha", &PAstats.Palpha);				
		particle->QueryFloatAttribute("red", &PAstats.Pred);				
		particle->QueryFloatAttribute("green", &PAstats.Pgreen);			
		particle->QueryFloatAttribute("blue", &PAstats.Pblue);				
		particle->QueryFloatAttribute("rotationx", &PAstats.Protationx);	
		particle->QueryFloatAttribute("rotationy", &PAstats.Protationy);	
		particle->QueryFloatAttribute("scalex", &PAstats.Pscalex);			
		particle->QueryFloatAttribute("scaley", &PAstats.Pscaley);			
	}

	TiXmlElement* flyweight = particle->NextSiblingElement("FlyWeight");


	//Set values for failure case
	FWstats.FWimageID = " ";
	FWstats.FWalpha = -1;
	FWstats.FWred = -1;
	FWstats.FWgreen = -1;
	FWstats.FWblue = -1;
	FWstats.FWscale = -1;
	FWstats.FWrotation = -1;
	FWstats.FWvelocity = -1;

	if (flyweight != nullptr)
	{
		//For the Flyweight
		const char* text = flyweight->Attribute("imageID");
		FWstats.FWimageID = new char[strlen(text) + 1];
		strcpy_s(FWstats.FWimageID, strlen(text) + 1, text);
		//FWstats.FWimageID = (char*)flyweight->Attribute("imageID");

		flyweight->QueryFloatAttribute("alpha", &FWstats.FWalpha);
		flyweight->QueryFloatAttribute("red", &FWstats.FWred);
		flyweight->QueryFloatAttribute("green", &FWstats.FWgreen);
		flyweight->QueryFloatAttribute("blue", &FWstats.FWblue);
		flyweight->QueryFloatAttribute("scale", &FWstats.FWscale);
		flyweight->QueryFloatAttribute("rotation", &FWstats.FWrotation);
		flyweight->QueryFloatAttribute("velocity", &FWstats.FWvelocity);
	}


	

	return true;
}

void ParticleSystem::Render()
{
	unsigned char TheNewAlpha;
	unsigned char TheNewRed;
	unsigned char TheNewGreen;
	unsigned char TheNewBlue;
	//Rendering

	for (unsigned int x = 0; x < PEstats.size(); x++)
	{
		TheNewAlpha = static_cast<unsigned char>(PEstats[x].PEalpha1);
		TheNewRed = static_cast<unsigned char>(PEstats[x].PEred1);
		TheNewGreen = static_cast<unsigned char>(PEstats[x].PEgreen1);
		TheNewBlue = static_cast<unsigned char>(PEstats[x].PEblue1);


		SGD::GraphicsManager::GetInstance()->DrawTexture(m_PShapes, SGD::Point(PEstats[x].PEposx, PEstats[x].PEposy), PEstats[x].PErotation, SGD::Vector(PEstats[x].PEwidth1, PEstats[x].PEheight1),
			SGD::Color(TheNewAlpha, TheNewRed, TheNewGreen, TheNewBlue));

		//SGD::GraphicsManager::GetInstance()->DrawTexture(m_PShapes, SGD::Point(PEstats[x].PEposx, PEstats[x].PEposy), PEstats[x].PErotation, SGD::Vector(PEstats[x].PEwidth1, PEstats[x].PEheight1),
		//	SGD::Color(TheNewAlpha, TheNewRed, TheNewGreen, TheNewBlue));
		
	}


}


void ParticleSystem::Update(float elapsedTime)//How to do the update function
{
	

	myTime += elapsedTime;

	while (myTime >= EMstats.EMspawnrate)
	{
		CreateParticle();//Create a CreateParticle Function
		myTime -= EMstats.EMspawnrate;
	}

	int randLifetimer;
	int temp;
	// Updating Particle Effects //
	for (unsigned int x = 0; x < PEstats.size(); x++)
	{
		 temp = (int) PEstats[x].PElifetimer;

		randLifetimer = rand() % temp;
		randLifetimer -= (int)elapsedTime;//PEstats[x].PElifetimer -= elapsedTime;
		


		//When its life timer reaches 0, delete it
		if (randLifetimer/*PEstats[x].PElifetimer*/ <= 0.0f)
		{
			ParticleEffect temp = PEstats[x];
			PEstats[x] = PEstats[PEstats.size() - 1];
			//PEstats[PEstats.size() - 1] = temp;
			PEstats.pop_back();
			x--;
			continue;
		}


		PEstats[x].PEposx += PAstats.Pvelocityx * elapsedTime;
		PEstats[x].PEposy += PAstats.Pvelocityy * elapsedTime;

		SGD::Color target((char)PEstats[x].PEalpha2, (char)PEstats[x].PEred2, (char)PEstats[x].PEgreen2, (char)PEstats[x].PEblue2);
		SGD::Color start((char)FWstats.FWalpha, (char)FWstats.FWred, (char)FWstats.FWgreen, (char)FWstats.FWblue);

		float delta_alpha = (float)(target.alpha - start.alpha);
		float delta_red = (float)(target.red - start.red);
		float delta_green =(float)( target.green - start.green);
		float delta_blue = (float)(target.blue - start.blue);
		float delta_rotation = (float)(PAstats.Protationx - FWstats.FWrotation);

		float t = (PAstats.Plifetimer - randLifetimer/*PEstats[x].PElifetimer*/) / PAstats.Plifetimer;

		PEstats[x].PEalpha1 = delta_alpha * t + start.alpha;
		PEstats[x].PEred1 = delta_red * t + start.red;
		PEstats[x].PEgreen1 = delta_green * t + start.green;
		PEstats[x].PEblue1 = delta_blue * t + start.blue;
		//PEstats[x].PErotation = delta_rotation * t + PAstats.Protationx;
	}
}

void ParticleSystem::CreateParticle()
{

	if (EMstats.EMloop != 1)
		count++;

	if (count <= EMstats.EMmax)
	{
	
	if (PEstats.size() >= (size_t)EMstats.EMmax)
		return;

	ParticleEffect p;

	//Starting color
	p.PEalpha1 = FWstats.FWalpha;
	p.PEred1 = FWstats.FWred;
	p.PEblue1 = FWstats.FWblue;
	p.PEgreen1 = FWstats.FWgreen;

	//Ending color
	p.PEalpha2 = (float)PAstats.Palpha;
	p.PEred2 = PAstats.Pred;
	p.PEblue2 = PAstats.Pblue;
	p.PEgreen2 = PAstats.Pgreen;

	//Starting size
	p.PEheight1 = EMstats.EMheight;
	p.PEwidth1 = EMstats.EMwidth;

	//Ending size
	p.PEscalex = PAstats.Pscalex;
	p.PEscaley = PAstats.Pscaley;

	//Position of emitter
	switch (EMstats.EMshape)
	{
	default:
	case 1://point

		p.PEposx = EMstats.EMposx;
		p.PEposy = EMstats.EMposy;
		break;
	case 2: //elipse
	{
		int xradius = rand() % int(EMstats.EMwidth / 2);
		int yradius = rand() % int(EMstats.EMheight / 2);
		float radians = (rand() / (float)RAND_MAX) * 2.0f * SGD::PI;
		p.PEposx = EMstats.EMposx + cos(radians) * xradius;
		p.PEposy = EMstats.EMposy + sin(radians) * yradius;
		break;
	}
	case 3: //rectangle
		p.PEposx = EMstats.EMposx + (EMstats.EMwidth * (rand() / (float)RAND_MAX) - EMstats.EMwidth * 0.5f);
		p.PEposy = EMstats.EMposy + (EMstats.EMheight  * (rand() / (float)RAND_MAX) - EMstats.EMheight * 0.5f);
		break;

	case 4: //line
		int xradius = rand() % int(EMstats.EMwidth / 2);
		int yradius = rand() % int(EMstats.EMheight / 2);
		float radians = (rand() / RAND_MAX) * 2 * SGD::PI;
		float cosradians = cos(radians);
		float sinradians = sin(radians);
		p.PEposx = EMstats.EMposx + cosradians * xradius;
		p.PEposy = EMstats.EMposy + sinradians * yradius;
		break;

	}



	//other needed stats
	p.PErotation = PAstats.Protationx;
	p.PEshape = EMstats.EMshape;
	p.PEspawnrate = EMstats.EMspawnrate;
	p.PEvelocity = EMstats.EMvelocity;
	p.PElifetimer = PAstats.Plifetimer;
	p.PEloop = EMstats.EMloop;
	

	PEstats.push_back(p);
	}
	
}